package com.junmo.oauth.config.authorization;//package com.junmo.oauth.config.security.authorization;
//
//import com.junmo.oauth.module.system.dao.SysResourceRepository;
//import com.junmo.oauth.module.system.dao.SysRoleRepository;
//import com.junmo.oauth.module.system.entity.SysResource;
//import com.junmo.oauth.module.system.entity.SysRole;
//import lombok.AllArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.security.access.ConfigAttribute;
//import org.springframework.security.access.SecurityConfig;
//import org.springframework.security.web.FilterInvocation;
//import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
//import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
//import org.springframework.stereotype.Component;
//
//import javax.servlet.http.HttpServletRequest;
//import java.util.*;
//import java.util.concurrent.ConcurrentHashMap;
//
///**
// * 加载资源与权限的对应关系;
// * 实现FilterInvocationSecurityMetadataSource接口也是必须的。
// * 首先，这里从数据库中获取信息,其中loadResourceDefine方法不是必须的，
// *  这个只是加载所有的资源与权限的对应关系并缓存起来，避免每次获取权限都访问数据库（提高性能），然后getAttributes根据参数（被拦截url）返回权限集合。
// *  这种缓存的实现其实有一个缺点，因为loadResourceDefine方法是放在构造器上调用的，
// *  而这个类的实例化只在web服务器启动时调用一次，那就是说loadResourceDefine方法只会调用一次，
// *  如果资源和权限的对应关系在启动后发生了改变，那么缓存起来的权限数据就和实际授权数据不一致，那就会授权错误了。
// *  但如果资源和权限对应关系是不会改变的，这种方法性能会好很多。
// *  要想解决 权限数据的一致性 可以直接在getAttributes方法里面调用数据库操作获取权限数据，
// *  通过被拦截url获取数据库中的所有权限，封装成Collection<ConfigAttribute>返回就行了。（灵活、简单
// *
// *  启动加载顺序：1：调用loadResourceDefine()方法  2：调用supports()方法   3：调用getAllConfigAttributes()方法
// */
//@Component
//@Slf4j
//@AllArgsConstructor
//public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {
//    private SysResourceRepository sysResourceRepository;
//    private SysRoleRepository sysRoleRepository;
//    //存放资源配置对象
//    private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
//    /**
//     * 此方法是为了判定用户请求的url 是否在权限表中，如果在权限表中，则返回给 decide 方法，用来判定用户是否有此权限。
//     * 如果不在权限表中则放行。
//     *
//     * 获取某个受保护的安全对象object的所需要的权限信息,是一组ConfigAttribute对象的集合，
//     * 如果该安全对象object不被当前SecurityMetadataSource对象支持,则抛出异常IllegalArgumentException。
//     * 该方法通常配合boolean supports(Class<?> clazz)一起使用，
//     * 先使用boolean supports(Class<?> clazz)确保安全对象能被当前SecurityMetadataSource支持，然后再调用该方法。
//     * @param object
//     * @return
//     * @throws IllegalArgumentException
//     */
//    @Override
//    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
//        log.info("--------FilterInvocationSecurityMetadataSource-----------\n object : "+ object);
//        loadResourceDefine();  // 每次请求 都会去数据库查询权限  貌似很耗性能
//        //object 中包含用户请求的request 信息
//        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
//        String url = ((FilterInvocation) object).getRequestUrl();
//        Iterator<String> ite = resourceMap.keySet().iterator();
//        while (ite.hasNext()) {
//            String resURL = ite.next();
//            AntPathRequestMatcher matcher = new AntPathRequestMatcher(resURL);
//            if(matcher.matches(request)) {
//                return resourceMap.get(resURL);
//            }
//        }
//        return null;
////        AntPathMatcher antPathMatcher = new AntPathMatcher();
////        String requestUrl = ((FilterInvocation) object).getRequestUrl();
////        List<SysResource> resources = sysResourceRepository.findAll();
////        for (SysResource resource : resources) {
////            if (antPathMatcher.match(resource.getResourceLink(), requestUrl)) {
////                List<SysRole> roles = sysRoleRepository.findByResourceId(resource.getResourceId());
////                Collection<ConfigAttribute> array= new ArrayList<>();
////                roles.forEach(role->array.add(new SecurityConfig("ROLE_"+role.getRoleCode())));
////                return array;
////            }
////        }
//////        return SecurityConfig.createList("ROLE_anonymous");
////        return SecurityConfig.createList("ROLE_admin");
//////        return Stream.of( new SecurityConfig("ROLE_anonymous")).collect(Collectors.toList());
//    }
//
//    /**
//     * 获取该SecurityMetadataSource对象中保存的针对所有安全对象的权限信息的集合。
//     * 该方法的主要目的是被AbstractSecurityInterceptor用于启动时校验每个ConfigAttribute对象。
//     */
//    @Override
//    public Collection<ConfigAttribute> getAllConfigAttributes() {
//        return null;
//    }
//
//    /**
//     * 这里clazz表示安全对象的类型，该方法用于告知调用者当前SecurityMetadataSource是否支持此类安全对象，
//     * 只有支持的时候，才能对这类安全对象调用getAttributes方法。
//     */
//    @Override
//    public boolean supports(Class<?> aClass) {
//        return true;
//    }
//
//    /**
//     * 加载权限表中所有权限.
//     *
//     * 初始化资源 ,提取系统中的所有权限，加载所有url和权限（或角色）的对应关系，web容器启动就会执行
//     * 如果启动@PostConstruct 注解 ,则web容器启动就会执行
//     *
//     */
//    //@PostConstruct
//    public void loadResourceDefine(){
//        //应当是资源为key， 权限为value。 资源通常为url， 权限就是那些以ROLE_为前缀的角色。 一个资源可以由多个权限来访问。
//        resourceMap = new ConcurrentHashMap<>();
//        List<SysResource> resources = sysResourceRepository.findAll();
//        for (SysResource resource : resources) {
//            List<SysRole> roles = sysRoleRepository.findByResourceId(resource.getResourceId());
//            Collection<ConfigAttribute> array= new ArrayList<>();
//            roles.forEach(role->array.add(new SecurityConfig("ROLE_"+role.getRoleCode())));
//            resourceMap.put(resource.getResourceLink(),array);//url:roles
//
//        }
//    }
//}
//
//
